package com.xiaoxi.xirpc.serializer;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiaoxi.xirpc.model.RpcRequest;
import com.xiaoxi.xirpc.model.RpcResponse;

import java.io.IOException;

/**
 *  Json序列化器
 */
public class JsonSerializer implements Serializer{
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    /**
     *  序列化
     * @param object
     * @return
     * @param <T>
     * @throws IOException
     */
    @Override
    public <T> byte[] serializer(T object) throws IOException {
        return OBJECT_MAPPER.writeValueAsBytes(object);
    }

    /**
     *  反序列化
     * @param bytes
     * @param type
     * @return
     * @param <T>
     * @throws IOException
     */
    @Override
    public <T> T deserialize(byte[] bytes, Class<T> type) throws IOException {
        T obj = OBJECT_MAPPER.readValue(bytes, type);
        if (obj instanceof RpcRequest){
            return handleRequest((RpcRequest) obj, type);
        }
        if (obj instanceof RpcResponse){
            return handleResponse((RpcResponse) obj, type);
        }
        return obj;
    }

    /**
     *  由于Object的原始对象会被擦除，导致反序列化会被当作LinkedHashMap，无法换成原始对象，所以对此做特殊处理
     * @param rpcResponse
     * @param type
     * @return
     * @param <T>
     * @throws IOException
     */
    private <T> T handleResponse(RpcResponse rpcResponse, Class<T> type) throws IOException {
        // 处理响应数据
        byte[] dataBytes = OBJECT_MAPPER.writeValueAsBytes(rpcResponse.getData());
        rpcResponse.setData(OBJECT_MAPPER.readValue(dataBytes, rpcResponse.getDatatype()));
        return type.cast(rpcResponse);
    }

    /**
     *  由于Object的原始对象会被擦除，导致反序列化会被当作LinkedHashMap，无法换成原始对象，所以对此做特殊处理
     * @param rpcRequest
     * @param type
     * @return
     * @param <T>
     * @throws IOException
     */
    private <T> T handleRequest(RpcRequest rpcRequest, Class<T> type) throws IOException {
        Class<?>[] parameterTypes = rpcRequest.getParameterTypes();
        Object[] args = rpcRequest.getArgs();

        // 循环处理每个参数的类型
        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> parameterType = parameterTypes[i];
            // 如果类型不同，则重新处理一下类型
            if (!parameterType.isAssignableFrom(args[i].getClass())){
                byte[] argsBytes = OBJECT_MAPPER.writeValueAsBytes(args[i]);
                args[i] = OBJECT_MAPPER.readValue(argsBytes, parameterType);
            }
        }
        return type.cast(rpcRequest);
    }
}
